<?php

namespace app\admin\service\crud;

use app\common\cache\ExportCache;
use tmcore\services\crud\enum\CrudEnum;
use app\common\model\crud\CrudTable;
use app\common\model\crud\CrudColumn;
use tmcore\base\BaseService;
use tmcore\exceptions\ValidateException;
use tmcore\services\crud\CrudService;
use tmcore\services\crud\UtilService;

class CodeService extends BaseService
{
    /**
     * 获取代码生成列表
     * @return array
     */
    public static function getList(): array
    {
        // 搜索条件
        $searchParam = [
            '%like%' => ['table_name']
        ];
        $where = self::getSearchData($searchParam);

        // 返回分页数据
        return CrudTable::page($where, self::getPageData(), '*', ['id' => 'desc']);
    }

    /**
     * 查看代码生成详情
     * @param $params
     * @return array
     */
    public static function detail($params): array
    {
        $data = CrudTable::where(['id' => $params['id']])->with('table_column')->findOrEmpty();
        if ($data->isEmpty()) return [];
        $data['table_prefix'] = config('database.connections.mysql.prefix');
        return $data->toArray();
    }

    /**
     * 代码预览
     * @param array $params
     * @return array|bool
     */
    public static function preview($params)
    {
        $row = CrudTable::where(['id' => $params['id']])->with('table_column')->findOrEmpty()->toArray();
        return (new CrudService)->preview($row);
    }

    /**
     * 生成代码
     * @param $params
     * @return array|bool
     */
    public static function generate($params)
    {
        self::beginTrans();
        try {
            // 查询生成列表
            $tables = CrudTable::with(['table_column'])
                ->whereIn('id', $params['id'])
                ->select()->toArray();

            $crudService = app()->make(CrudService::class);
            // 清空生成文件
            $crudService->clearCrudDirFile();
            // 循环生成
            foreach ($tables as $table) {
                $crudService->generate($table);
            }
            // 压缩文件
            $res = $crudService->zipFile();
            self::commitTrans();
            if ($res) {
                // 设置导出缓存
                (new ExportCache)->setExportDownload($res['identifier'], $res['url'], $res['name'], 1800);

                return ['crud_type' => 1, 'file_key' => $res['identifier'], 'file_name' => $res['name']];
            } else {
                return ['crud_type' => 2];
            }
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

    /**
     * 同步表结构
     * @param array $params
     * @param int $adminId
     * @return bool
     */
    public static function sync(array $params, int $adminId)
    {
        self::beginTrans();
        try {
            $row = CrudTable::findOrEmpty($params['id']);
            if ($row->isEmpty() || empty($row['table_name'])) throw new ValidateException('找不到同步的数据表');

            $tables = UtilService::queryTablesByName([['name' => $row['table_name']]]);
            if (empty($tables[0])) throw new ValidateException('未找到相关表信息');

            CrudColumn::whereIn('table_id', $row['id'])->delete();

            self::initTableData($params['id'], $tables[0], $adminId);

            self::commitTrans();
            return true;
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

    /**
     * 导入数据表
     * @param array $params
     * @param integer $adminId
     * @return bool
     */
    public static function import(array $params, int $adminId)
    {
        $tables = UtilService::queryTablesByName($params);
        if (!$tables || count($params) != count($tables)) {
            throw new ValidateException(!$tables ? '未找到相关表信息' : '部分表未能找到');
        }

        self::beginTrans();
        try {
            foreach ($tables as $table) {
                self::initTableData(0, $table, $adminId);
            }

            self::commitTrans();
            return true;
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

    /**
     * 初始化表数据
     * @param $id
     * @param $table
     * @param $adminId
     */
    private static function initTableData($id, $table, $adminId)
    {

        $data = [
            'table_name'     => $table['name'],
            'table_comment'  => $table['comment'],
            'module_name'    => 'admin',
            'class_name'     => UtilService::studly(UtilService::get_no_prefix_table_name($table['name'])),
            'tpl_type'       => CrudEnum::TPL_TYPE_SINGLE,
            'crud_type'      => CrudEnum::CRUD_TYPE_ZIP,
            'component_type' => CrudEnum::COMPONENT_TYPE_MODULE,
            'is_insert'      => CrudEnum::IS_INSERT_YES,
            'is_update'      => CrudEnum::IS_UPDATE_YES,
            'is_delete'      => CrudEnum::IS_DELETE_YES,
            'is_detail'      => CrudEnum::IS_DETAIL_NO,
            'menu'           => [
                'pid'  => 0,
                'type' => CrudEnum::MENU_MT,
                'name' => $table['comment'],
            ],
            'delete'         => [
                'type' => CrudEnum::DELETE_TRUE,
                'name' => CrudEnum::DELETE_NAME,
            ],
            'tree'           => [
                'id'   => '',
                'pid'  => '',
                'name' => '',
            ],
            'join'           => '',
            'admin_id'       => $adminId
        ];

        if (!$id) {
            // 添加生成表
            $curTable = CrudTable::create($data);
            $add_id   = $curTable['id'];
        } else {
            // 编辑生成表
            CrudTable::edit($data, $id);
            $add_id = $id;
        }

        // 添加生成字段表
        $columns = UtilService::queryColumnsByName($table['name']);
        foreach ($columns as $column) {
            $types            = explode('(', $column['type'])[0];
            $lengths          = explode('(', $column['type'])[1] ?? '0)';
            $lengths          = explode(')', trim($lengths))[0];
            $column['type']   = $types;
            $column['length'] = $lengths;

            $columnData = [
                'table_id'       => $add_id,
                'column_name'    => $column['name'],
                'column_comment' => $column['comment'],
                'column_length'  => trim($lengths),
                'column_type'    => trim($types),
                'is_pk'          => $column['primary'] ? 1 : 0,
                'query_type'     => UtilService::handleQueryType($column),
                'view_type'      => UtilService::handleFormType($column),
                'dict_type'      => '',
                'extra'          => ''
            ];

            if (empty($column['primary']) && (!in_array(strtolower($column['name']), UtilService::getIgnoreFields()))) {
                $columnData['is_required'] = 1;
                $columnData['is_insert']   = 1;
                $columnData['is_update']   = 1;
                $columnData['is_list']     = 1;
                $columnData['is_query']    = 1;
            }
            CrudColumn::create($columnData);
        }
    }

    /**
     * 编辑代码生成
     * @param array $params
     * @return bool
     */
    public static function edit(array $params): bool
    {
        self::beginTrans();
        try {

            CrudTable::edit([
                'table_name'     => $params['table_name'],
                'table_comment'  => $params['table_comment'],
                'author'         => $params['author'] ?? '',
                'remark'         => $params['remark'] ?? '',
                'module_name'    => $params['module_name'],
                'class_folder'   => $params['class_folder'],
                'class_name'     => $params['class_name'],
                'tpl_type'       => $params['tpl_type'],
                'crud_type'      => $params['crud_type'],
                'component_type' => $params['component_type'],
                'is_insert'      => $params['is_insert'],
                'is_update'      => $params['is_update'],
                'is_delete'      => $params['is_delete'],
                'is_detail'      => $params['is_detail'],
                'is_export'      => $params['is_export'],
                'is_import'      => $params['is_import'],
                'menu'           => $params['menu'],
                'delete'         => $params['delete'],
                'tree'           => $params['tree'],
                'join'           => $params['join'],
            ], $params['id']);

            foreach ($params['table_column'] as $column) {
                CrudColumn::edit([
                    'column_name'    => $column['column_name'],
                    'column_comment' => $column['column_comment'],
                    'is_required'    => $column['is_required'],
                    'is_insert'      => $column['is_insert'],
                    'is_update'      => $column['is_update'],
                    'is_list'        => $column['is_list'],
                    'is_query'       => $column['is_query'],
                    'is_detail'      => $column['is_detail'],
                    'query_type'     => $column['query_type'],
                    'view_type'      => $column['view_type'],
                    'dict_type'      => $column['dict_type'] ?? '',
                    'extra'          => $column['extra'] ?? '',
                ], $column['id']);
            }

            self::commitTrans();
            return true;
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }


    /**
     * 删除代码生成
     * @param array $params
     * @return bool
     */
    public static function delete(array $params)
    {
        self::beginTrans();
        try {
            CrudTable::whereIn('id', $params['id'])->delete();
            CrudColumn::whereIn('table_id', $params['id'])->delete();

            self::commitTrans();
            return true;
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

}